+++ /dev/null
-.details-button image {
- transition: 250ms;
-}
-.details-button.expanded:dir(ltr) image {
- -gtk-icon-transform: rotate(0.25turn);
-}
-.details-button.expanded:dir(rtl) image {
- -gtk-icon-transform: rotate(-0.25turn);
-}
-
-image.warning { color: @warning_color; }
--- /dev/null
+.details-button image {
+ transition: 250ms;
+}
+.details-button.expanded:dir(ltr) image {
+ -gtk-icon-transform: rotate(0.25turn);
+}
+.details-button.expanded:dir(rtl) image {
+ -gtk-icon-transform: rotate(-0.25turn);
+}
+
+image.warning { color: @warning_color; }
--- /dev/null
+gnome.compile_resources(
+ app_id + '.data',
+ app_id + '.data.gresource.xml',
+ gresource_bundle: true,
+ install: true,
+ install_dir: pkgdatadir
+)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/Extensions">
+ <file>css/application.css</file>
+
+ <file>ui/extension-row.ui</file>
+ <file>ui/extensions-window.ui</file>
+ </gresource>
+</gresources>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.0 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <template class="ExtensionRow" parent="GtkListBoxRow">
+ <property name="visible">True</property>
+ <property name="activatable">False</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="margin">12</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="nameLabel">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage" id="updatesIcon">
+ <property name="no_show_all">True</property>
+ <property name="icon_name">software-update-available-symbolic</property>
+ <style>
+ <class name="warning"/>>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="hexpand">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="prefsButton">
+ <property name="no_show_all">True</property>
+ <property name="visible"
+ bind-source="prefsButton"
+ bind-property="sensitive"
+ bind-flags="sync-create"/>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="valign">center</property>
+ <property name="action-name">row.show-prefs</property>
+ <style>
+ <class name="circular"/>>
+ <class name="image-button"/>>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">emblem-system-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSwitch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">center</property>
+ <property name="action-name">row.enabled</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="revealButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="details-button"/>
+ <class name="image-button"/>
+ <class name="flat"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">pan-end-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkRevealer" id="revealer">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="margin_top">12</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Description</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="descriptionLabel">
+ <property name="visible">True</property>
+ <property name="ellipsize">end</property>
+ <property name="max_width_chars">60</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible"
+ bind-source="versionLabel"
+ bind-property="visible"
+ bind-flags="sync-create"/>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">Version</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="versionLabel">
+ <property name="no_show_all">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible"
+ bind-source="authorLabel"
+ bind-property="visible"
+ bind-flags="sync-create"/>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">Author</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="authorLabel">
+ <property name="no_show_all">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Website</property>
+ <property name="action_name">row.show-url</property>
+ <property name="valign">end</property>
+ <property name="margin-top">12</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="removeButton">
+ <property name="visible"
+ bind-source="removeButton"
+ bind-property="sensitive"
+ bind-flags="sync-create"/>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">Remove…</property>
+ <property name="action_name">row.uninstall</property>
+ <property name="hexpand">True</property>
+ <property name="halign">end</property>
+ <property name="valign">end</property>
+ <style>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">7</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.0 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <menu id="primary-menu">
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">Help</attribute>
+ <attribute name="action">win.show-help</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">About Extensions</attribute>
+ <attribute name="action">win.show-about</attribute>
+ </item>
+ </section>
+ </menu>
+ <object class="GtkPopover" id="infoPopover">
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="margin">12</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">To find and add extensions, visit <a href="https://extensions.gnome.org">extensions.gnome.org</a>.</property>
+ <property name="use_markup">True</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Warning</property>
+ <property name="xalign">0</property>
+ <property name="margin_top">6</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Extensions can cause system issues, including performance problems. If you encounter problems with your system, it is recommended to disable all extensions.</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">40</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <template class="ExtensionsWindow" parent="GtkApplicationWindow">
+ <property name="default_width">800</property>
+ <property name="default_height">500</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Extensions</property>
+ <property name="show_close_button">True</property>
+ <child>
+ <object class="GtkMenuButton">
+ <property name="visible">True</property>
+ <property name="popover">infoPopover</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">dialog-information-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="menuButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="menu_model">primary-menu</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">open-menu-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="killSwitch">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="mainStack">
+ <property name="visible">True</property>
+ <property name="transition_type">crossfade</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledWindow">
+ <property name="visible">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkBox" id="mainBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="halign">center</property>
+ <property name="margin">36</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible"
+ bind-source="userList"
+ bind-property="visible"
+ bind-flags="sync-create"/>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes">Manually Installed</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="userList">
+ <property name="visible">True</property>
+ <property name="selection_mode">none</property>
+ <property name="margin_bottom">24</property>
+ <style>
+ <class name="frame"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible"
+ bind-source="systemList"
+ bind-property="visible"
+ bind-flags="sync-create"/>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes">Built-In</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBox" id="systemList">
+ <property name="visible">True</property>
+ <property name="selection_mode">none</property>
+ <style>
+ <class name="frame"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">main</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="margin">32</property>
+ <property name="spacing">6</property>
+ <property name="valign">center</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="pixel_size">96</property>
+ <property name="icon_name">org.gnome.Extensions-symbolic</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">No Installed Extensions</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="scale" value="1.44"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">placeholder</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="margin_left">100</property>
+ <property name="margin_right">100</property>
+ <property name="margin_top">100</property>
+ <property name="margin_bottom">60</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Something’s gone wrong</property>
+ <attributes>
+ <attribute name="scale" value="1.44"/>
+ </attributes>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">We’re very sorry, but it was not possible to get the list of installed extensions. Make sure you are logged into GNOME and try again.</property>
+ <property name="justify">center</property>
+ <property name="wrap">True</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">noshell</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkActionBar" id="updatesBar">
+ <property name="no_show_all">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="pixel-size">24</property>
+ <property name="margin">6</property>
+ <property name="icon_name">software-update-available-symbolic</property>
+ <style>
+ <class name="warning"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="label">Extension Updates Ready</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="updatesLabel">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="label" translatable="yes">Log Out…</property>
+ <property name="visible">True</property>
+ <property name="valign">center</property>
+ <property name="action-name">win.logout</property>
+ <property name="receives_default">True</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+++ /dev/null
-#!/bin/sh
-@gjs@ @pkgdatadir@/@app_id@ "$@"
--- /dev/null
+#!/bin/sh
+@gjs@ @pkgdatadir@/@app_id@ "$@"
--- /dev/null
+/* exported main */
+imports.gi.versions.Gdk = '3.0';
+imports.gi.versions.Gtk = '3.0';
+
+imports.package.initFormat();
+
+const Gettext = imports.gettext;
+const { Gdk, GLib, Gio, GObject, Gtk } = imports.gi;
+
+const _ = Gettext.gettext;
+
+const ExtensionUtils = imports.misc.extensionUtils;
+const { loadInterfaceXML } = imports.misc.fileUtils;
+
+const { ExtensionState, ExtensionType } = ExtensionUtils;
+
+const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
+const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
+
+function stripPrefix(string, prefix) {
+ if (string.slice(0, prefix.length) == prefix)
+ return string.slice(prefix.length);
+ return string;
+}
+
+var Application = GObject.registerClass(
+class Application extends Gtk.Application {
+ _init() {
+ GLib.set_prgname('gnome-shell-extension-prefs');
+ super._init({
+ application_id: 'org.gnome.Extensions',
+ flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
+ });
+ }
+
+ get shellProxy() {
+ return this._shellProxy;
+ }
+
+ vfunc_activate() {
+ this._shellProxy.CheckForUpdatesRemote();
+ this._window.present();
+ }
+
+ vfunc_startup() {
+ super.vfunc_startup();
+
+ let provider = new Gtk.CssProvider();
+ let uri = 'resource:///org/gnome/Extensions/css/application.css';
+ try {
+ provider.load_from_file(Gio.File.new_for_uri(uri));
+ } catch (e) {
+ logError(e, 'Failed to add application style');
+ }
+ Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
+ provider,
+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
+ this._window = new ExtensionsWindow({ application: this });
+ }
+
+ vfunc_command_line(commandLine) {
+ let [prgName_, uuid] = commandLine.get_arguments();
+
+ if (uuid) {
+ // Strip off "extension:///" prefix which fakes a URI, if it exists
+ uuid = stripPrefix(uuid, 'extension:///');
+
+ this._window.openPrefs(uuid);
+ } else {
+ this.activate();
+ }
+ return 0;
+ }
+});
+
+var ExtensionsWindow = GObject.registerClass({
+ GTypeName: 'ExtensionsWindow',
+ Template: 'resource:///org/gnome/Extensions/ui/extensions-window.ui',
+ InternalChildren: [
+ 'userList',
+ 'systemList',
+ 'killSwitch',
+ 'mainBox',
+ 'mainStack',
+ 'scrolledWindow',
+ 'updatesBar',
+ 'updatesLabel',
+ ],
+}, class ExtensionsWindow extends Gtk.ApplicationWindow {
+ _init(params) {
+ super._init(params);
+
+ this._startupUuid = null;
+ this._loaded = false;
+ this._prefsDialog = null;
+ this._updatesCheckId = 0;
+
+ this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment);
+
+ let action;
+ action = new Gio.SimpleAction({ name: 'show-about' });
+ action.connect('activate', this._showAbout.bind(this));
+ this.add_action(action);
+
+ action = new Gio.SimpleAction({ name: 'logout' });
+ action.connect('activate', this._logout.bind(this));
+ this.add_action(action);
+
+ this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
+ this._settings.bind('disable-user-extensions',
+ this._killSwitch, 'active',
+ Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
+
+ this._userList.set_sort_func(this._sortList.bind(this));
+ this._userList.set_header_func(this._updateHeader.bind(this));
+
+ this._systemList.set_sort_func(this._sortList.bind(this));
+ this._systemList.set_header_func(this._updateHeader.bind(this));
+
+ this._shellProxy.connectSignal('ExtensionStateChanged',
+ this._onExtensionStateChanged.bind(this));
+
+ this._scanExtensions();
+ }
+
+ get _shellProxy() {
+ return this.application.shellProxy;
+ }
+
+ uninstall(uuid) {
+ let row = this._findExtensionRow(uuid);
+
+ let dialog = new Gtk.MessageDialog({
+ transient_for: this,
+ modal: true,
+ text: _('Remove “%s”?').format(row.name),
+ secondary_text: _('If you remove the extension, you need to return to download it if you want to enable it again'),
+ });
+
+ dialog.add_button(_('Cancel'), Gtk.ResponseType.CANCEL);
+ dialog.add_button(_('Remove'), Gtk.ResponseType.ACCEPT)
+ .get_style_context().add_class('destructive-action');
+
+ dialog.connect('response', (dlg, response) => {
+ if (response === Gtk.ResponseType.ACCEPT)
+ this._shellProxy.UninstallExtensionRemote(uuid);
+ dialog.destroy();
+ });
+ dialog.present();
+ }
+
+ openPrefs(uuid) {
+ if (!this._loaded)
+ this._startupUuid = uuid;
+ else if (!this._showPrefs(uuid))
+ this.present();
+ }
+
+ _showPrefs(uuid) {
+ if (this._prefsDialog)
+ return false;
+
+ let row = this._findExtensionRow(uuid);
+ if (!row || !row.hasPrefs)
+ return false;
+
+ let widget;
+
+ try {
+ widget = row.prefsModule.buildPrefsWidget();
+ } catch (e) {
+ widget = this._buildErrorUI(row, e);
+ }
+
+ this._prefsDialog = new Gtk.Window({
+ application: this.application,
+ default_width: 600,
+ default_height: 400,
+ modal: this.visible,
+ type_hint: Gdk.WindowTypeHint.DIALOG,
+ window_position: Gtk.WindowPosition.CENTER,
+ });
+
+ this._prefsDialog.set_titlebar(new Gtk.HeaderBar({
+ show_close_button: true,
+ title: row.name,
+ visible: true,
+ }));
+
+ if (this.visible)
+ this._prefsDialog.transient_for = this;
+
+ this._prefsDialog.connect('destroy', () => {
+ this._prefsDialog = null;
+
+ if (!this.visible)
+ this.destroy();
+ });
+
+ this._prefsDialog.add(widget);
+ this._prefsDialog.show();
+
+ return true;
+ }
+
+ _showAbout() {
+ let aboutDialog = new Gtk.AboutDialog({
+ authors: [
+ 'Florian Müllner <fmuellner@gnome.org>',
+ 'Jasper St. Pierre <jstpierre@mecheye.net>',
+ 'Didier Roche <didrocks@ubuntu.com>',
+ ],
+ translator_credits: _('translator-credits'),
+ program_name: _('Extensions'),
+ comments: _('Manage your GNOME Extensions'),
+ license_type: Gtk.License.GPL_2_0,
+ logo_icon_name: 'org.gnome.Extensions',
+ version: imports.package.version,
+
+ transient_for: this,
+ modal: true,
+ });
+ aboutDialog.present();
+ }
+
+ _logout() {
+ this.application.get_dbus_connection().call(
+ 'org.gnome.SessionManager',
+ '/org/gnome/SessionManager',
+ 'org.gnome.SessionManager',
+ 'Logout',
+ new GLib.Variant('(u)', [0]),
+ null,
+ Gio.DBusCallFlags.NONE,
+ -1,
+ null,
+ (o, res) => {
+ o.call_finish(res);
+ });
+ }
+
+ _buildErrorUI(row, exc) {
+ let scroll = new Gtk.ScrolledWindow({
+ hscrollbar_policy: Gtk.PolicyType.NEVER,
+ propagate_natural_height: true,
+ });
+
+ let box = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ spacing: 12,
+ margin: 100,
+ margin_bottom: 60,
+ });
+ scroll.add(box);
+
+ let label = new Gtk.Label({
+ label: '<span size="x-large">%s</span>'.format(_("Something’s gone wrong")),
+ use_markup: true,
+ });
+ label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
+ box.add(label);
+
+ label = new Gtk.Label({
+ label: _("We’re very sorry, but there’s been a problem: the settings for this extension can’t be displayed. We recommend that you report the issue to the extension authors."),
+ justify: Gtk.Justification.CENTER,
+ wrap: true,
+ });
+ box.add(label);
+
+ let expander = new Expander({
+ label: _("Technical Details"),
+ margin_top: 12,
+ });
+ box.add(expander);
+
+ let errortext = '%s\n\nStack trace:\n'.format(exc);
+ // Indent stack trace.
+ errortext +=
+ exc.stack.split('\n').map(line => ' %s'.format(line)).join('\n');
+
+ let buffer = new Gtk.TextBuffer({ text: errortext });
+ let textview = new Gtk.TextView({
+ buffer,
+ wrap_mode: Gtk.WrapMode.WORD,
+ monospace: true,
+ editable: false,
+ top_margin: 12,
+ bottom_margin: 12,
+ left_margin: 12,
+ right_margin: 12,
+ });
+
+ let toolbar = new Gtk.Toolbar();
+ let provider = new Gtk.CssProvider();
+ provider.load_from_data(`* {
+ border: 0 solid @borders;
+ border-top-width: 1px;
+ }`);
+ toolbar.get_style_context().add_provider(
+ provider,
+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
+ );
+
+ let copyButton = new Gtk.ToolButton({
+ icon_name: 'edit-copy-symbolic',
+ tooltip_text: _("Copy Error"),
+ });
+ toolbar.add(copyButton);
+
+ copyButton.connect('clicked', w => {
+ let clipboard = Gtk.Clipboard.get_default(w.get_display());
+ // markdown for pasting in gitlab issues
+ let lines = [
+ 'The settings of extension %s had an error:'.format(row.uuid),
+ '```', // '`' (xgettext throws up on odd number of backticks)
+ exc.toString(),
+ '```', // '`'
+ '',
+ 'Stack trace:',
+ '```', // '`'
+ exc.stack.replace(/\n$/, ''), // stack without trailing newline
+ '```', // '`'
+ '',
+ ];
+ clipboard.set_text(lines.join('\n'), -1);
+ });
+
+ let spacing = new Gtk.SeparatorToolItem({ draw: false });
+ toolbar.add(spacing);
+ toolbar.child_set_property(spacing, "expand", true);
+
+ let urlButton = new Gtk.ToolButton({
+ label: _("Homepage"),
+ tooltip_text: _("Visit extension homepage"),
+ no_show_all: true,
+ visible: row.url !== '',
+ });
+ toolbar.add(urlButton);
+
+ urlButton.connect('clicked', w => {
+ let context = w.get_display().get_app_launch_context();
+ Gio.AppInfo.launch_default_for_uri(row.url, context);
+ });
+
+ let expandedBox = new Gtk.Box({
+ orientation: Gtk.Orientation.VERTICAL,
+ });
+ expandedBox.add(textview);
+ expandedBox.add(toolbar);
+
+ expander.add(expandedBox);
+
+ scroll.show_all();
+ return scroll;
+ }
+
+ _sortList(row1, row2) {
+ return row1.name.localeCompare(row2.name);
+ }
+
+ _updateHeader(row, before) {
+ if (!before || row.get_header())
+ return;
+
+ let sep = new Gtk.Separator({ orientation: Gtk.Orientation.HORIZONTAL });
+ row.set_header(sep);
+ }
+
+ _findExtensionRow(uuid) {
+ return [
+ ...this._userList.get_children(),
+ ...this._systemList.get_children(),
+ ].find(c => c.uuid === uuid);
+ }
+
+ _onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
+ let extension = ExtensionUtils.deserializeExtension(newState);
+ let row = this._findExtensionRow(uuid);
+
+ this._queueUpdatesCheck();
+
+ // the extension's type changed; remove the corresponding row
+ // and reset the variable to null so that we create a new row
+ // below and add it to the appropriate list
+ if (row && row.type !== extension.type) {
+ row.destroy();
+ row = null;
+ }
+
+ if (row) {
+ if (extension.state === ExtensionState.UNINSTALLED)
+ row.destroy();
+ return; // we only deal with new and deleted extensions here
+ }
+ this._addExtensionRow(extension);
+ }
+
+ _scanExtensions() {
+ this._shellProxy.ListExtensionsRemote(([extensionsMap], e) => {
+ if (e) {
+ if (e instanceof Gio.DBusError) {
+ log('Failed to connect to shell proxy: %s'.format(e.toString()));
+ this._mainStack.visible_child_name = 'noshell';
+ } else {
+ throw e;
+ }
+ return;
+ }
+
+ for (let uuid in extensionsMap) {
+ let extension = ExtensionUtils.deserializeExtension(extensionsMap[uuid]);
+ this._addExtensionRow(extension);
+ }
+ this._extensionsLoaded();
+ });
+ }
+
+ _addExtensionRow(extension) {
+ let row = new ExtensionRow(extension);
+ row.show_all();
+
+ if (row.type === ExtensionType.PER_USER)
+ this._userList.add(row);
+ else
+ this._systemList.add(row);
+ }
+
+ _queueUpdatesCheck() {
+ if (this._updatesCheckId)
+ return;
+
+ this._updatesCheckId = GLib.timeout_add_seconds(
+ GLib.PRIORITY_DEFAULT, 1, () => {
+ this._checkUpdates();
+
+ this._updatesCheckId = 0;
+ return GLib.SOURCE_REMOVE;
+ });
+ }
+
+ _checkUpdates() {
+ let nUpdates = this._userList.get_children().filter(c => c.hasUpdate).length;
+
+ this._updatesLabel.label = Gettext.ngettext(
+ '%d extension will be updated on next login.',
+ '%d extensions will be updated on next login.',
+ nUpdates).format(nUpdates);
+ this._updatesBar.visible = nUpdates > 0;
+ }
+
+ _extensionsLoaded() {
+ this._userList.visible = this._userList.get_children().length > 0;
+ this._systemList.visible = this._systemList.get_children().length > 0;
+
+ if (this._userList.visible || this._systemList.visible)
+ this._mainStack.visible_child_name = 'main';
+ else
+ this._mainStack.visible_child_name = 'placeholder';
+
+ this._checkUpdates();
+
+ if (this._startupUuid)
+ this._showPrefs(this._startupUuid);
+ this._startupUuid = null;
+ this._loaded = true;
+ }
+});
+
+var Expander = GObject.registerClass({
+ Properties: {
+ 'label': GObject.ParamSpec.string(
+ 'label', 'label', 'label',
+ GObject.ParamFlags.READWRITE,
+ null
+ ),
+ },
+}, class Expander extends Gtk.Box {
+ _init(params = {}) {
+ this._labelText = null;
+
+ super._init(Object.assign(params, {
+ orientation: Gtk.Orientation.VERTICAL,
+ spacing: 0,
+ }));
+
+ this._frame = new Gtk.Frame({
+ shadow_type: Gtk.ShadowType.IN,
+ hexpand: true,
+ });
+
+ let eventBox = new Gtk.EventBox();
+ this._frame.add(eventBox);
+
+ let hbox = new Gtk.Box({
+ spacing: 6,
+ margin: 12,
+ });
+ eventBox.add(hbox);
+
+ this._arrow = new Gtk.Image({
+ icon_name: 'pan-end-symbolic',
+ });
+ hbox.add(this._arrow);
+
+ this._label = new Gtk.Label({ label: this._labelText });
+ hbox.add(this._label);
+
+ this._revealer = new Gtk.Revealer();
+
+ this._childBin = new Gtk.Frame({
+ shadow_type: Gtk.ShadowType.IN,
+ });
+ this._revealer.add(this._childBin);
+
+ // Directly chain up to parent for internal children
+ super.add(this._frame);
+ super.add(this._revealer);
+
+ let provider = new Gtk.CssProvider();
+ provider.load_from_data('* { border-top-width: 0; }');
+ this._childBin.get_style_context().add_provider(
+ provider,
+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
+ );
+
+ this._gesture = new Gtk.GestureMultiPress({
+ widget: this._frame,
+ button: 0,
+ exclusive: true,
+ });
+ this._gesture.connect('released', (gesture, nPress) => {
+ if (nPress == 1)
+ this._revealer.reveal_child = !this._revealer.reveal_child;
+ });
+ this._revealer.connect('notify::reveal-child', () => {
+ if (this._revealer.reveal_child)
+ this._arrow.icon_name = 'pan-down-symbolic';
+ else
+ this._arrow.icon_name = 'pan-end-symbolic';
+ });
+ }
+
+ get label() {
+ return this._labelText;
+ }
+
+ set label(text) {
+ if (this._labelText == text)
+ return;
+
+ if (this._label)
+ this._label.label = text;
+ this._labelText = text;
+ this.notify('label');
+ }
+
+ add(child) {
+ // set expanded child
+ this._childBin.get_children().forEach(c => {
+ this._childBin.remove(c);
+ });
+
+ if (child)
+ this._childBin.add(child);
+ }
+});
+
+var ExtensionRow = GObject.registerClass({
+ GTypeName: 'ExtensionRow',
+ Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui',
+ InternalChildren: [
+ 'nameLabel',
+ 'descriptionLabel',
+ 'versionLabel',
+ 'authorLabel',
+ 'updatesIcon',
+ 'revealButton',
+ 'revealer',
+ ],
+}, class ExtensionRow extends Gtk.ListBoxRow {
+ _init(extension) {
+ super._init();
+
+ this._app = Gio.Application.get_default();
+ this._extension = extension;
+ this._prefsModule = null;
+
+ this._actionGroup = new Gio.SimpleActionGroup();
+ this.insert_action_group('row', this._actionGroup);
+
+ let action;
+ action = new Gio.SimpleAction({
+ name: 'show-prefs',
+ enabled: this.hasPrefs,
+ });
+ action.connect('activate', () => this.get_toplevel().openPrefs(this.uuid));
+ this._actionGroup.add_action(action);
+
+ action = new Gio.SimpleAction({
+ name: 'show-url',
+ enabled: this.url !== '',
+ });
+ action.connect('activate', () => {
+ Gio.AppInfo.launch_default_for_uri(
+ this.url, this.get_display().get_app_launch_context());
+ });
+ this._actionGroup.add_action(action);
+
+ action = new Gio.SimpleAction({
+ name: 'uninstall',
+ enabled: this.type === ExtensionType.PER_USER,
+ });
+ action.connect('activate', () => this.get_toplevel().uninstall(this.uuid));
+ this._actionGroup.add_action(action);
+
+ action = new Gio.SimpleAction({
+ name: 'enabled',
+ state: new GLib.Variant('b', false),
+ });
+ action.connect('activate', () => {
+ let state = action.get_state();
+ action.change_state(new GLib.Variant('b', !state.get_boolean()));
+ });
+ action.connect('change-state', (a, state) => {
+ if (state.get_boolean())
+ this._app.shellProxy.EnableExtensionRemote(this.uuid);
+ else
+ this._app.shellProxy.DisableExtensionRemote(this.uuid);
+ });
+ this._actionGroup.add_action(action);
+
+ this._nameLabel.label = this.name;
+
+ let desc = this._extension.metadata.description.split('\n')[0];
+ this._descriptionLabel.label = desc;
+
+ this._revealButton.connect('clicked', () => {
+ this._revealer.reveal_child = !this._revealer.reveal_child;
+ });
+ this._revealer.connect('notify::reveal-child', () => {
+ if (this._revealer.reveal_child)
+ this._revealButton.get_style_context().add_class('expanded');
+ else
+ this._revealButton.get_style_context().remove_class('expanded');
+ });
+
+ this.connect('destroy', this._onDestroy.bind(this));
+
+ this._extensionStateChangedId = this._app.shellProxy.connectSignal(
+ 'ExtensionStateChanged', (p, sender, [uuid, newState]) => {
+ if (this.uuid !== uuid)
+ return;
+
+ this._extension = ExtensionUtils.deserializeExtension(newState);
+ this._updateState();
+ });
+ this._updateState();
+ }
+
+ get uuid() {
+ return this._extension.uuid;
+ }
+
+ get name() {
+ return this._extension.metadata.name;
+ }
+
+ get hasPrefs() {
+ return this._extension.hasPrefs;
+ }
+
+ get hasUpdate() {
+ return this._extension.hasUpdate || false;
+ }
+
+ get type() {
+ return this._extension.type;
+ }
+
+ get creator() {
+ return this._extension.metadata.creator || '';
+ }
+
+ get url() {
+ return this._extension.metadata.url || '';
+ }
+
+ get version() {
+ return this._extension.metadata.version || '';
+ }
+
+ _updateState() {
+ let state = this._extension.state === ExtensionState.ENABLED;
+
+ let action = this._actionGroup.lookup('enabled');
+ action.set_state(new GLib.Variant('b', state));
+ action.enabled = this._canToggle();
+
+ this._updatesIcon.visible = this.hasUpdate;
+
+ this._versionLabel.label = this.version.toString();
+ this._versionLabel.visible = this.version !== '';
+
+ this._authorLabel.label = this.creator.toString();
+ this._authorLabel.visible = this.creator !== '';
+ }
+
+ _onDestroy() {
+ if (!this._app.shellProxy)
+ return;
+
+ if (this._extensionStateChangedId)
+ this._app.shellProxy.disconnectSignal(this._extensionStateChangedId);
+ this._extensionStateChangedId = 0;
+ }
+
+ _canToggle() {
+ return this._extension.canChange;
+ }
+
+ get prefsModule() {
+ // give extension prefs access to their own extension object
+ ExtensionUtils.getCurrentExtension = () => this._extension;
+
+ if (!this._prefsModule) {
+ ExtensionUtils.installImporter(this._extension);
+
+ this._prefsModule = this._extension.imports.prefs;
+ this._prefsModule.init(this._extension.metadata);
+ }
+
+ return this._prefsModule;
+ }
+});
+
+function initEnvironment() {
+ // Monkey-patch in a "global" object that fakes some Shell utilities
+ // that ExtensionUtils depends on.
+ window.global = {
+ log(...args) {
+ print(args.join(', '));
+ },
+
+ logError(s) {
+ log('ERROR: %s'.format(s));
+ },
+
+ userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']),
+ };
+}
+
+function main(argv) {
+ initEnvironment();
+
+ new Application().run(argv);
+}
--- /dev/null
+launcherconf = configuration_data()
+launcherconf.set('app_id', app_id)
+launcherconf.set('PACKAGE_NAME', meson.project_name())
+launcherconf.set('PACKAGE_VERSION', meson.project_version())
+launcherconf.set('prefix', prefix)
+launcherconf.set('libdir', libdir)
+launcherconf.set('pkgdatadir', pkgdatadir)
+launcherconf.set('gjs', gjs.path())
+
+configure_file(
+ input: prgname + '.in',
+ output: prgname,
+ configuration: launcherconf,
+ install_dir: bindir,
+ install_mode: 'rwxr-xr-x',
+)
+
+configure_file(
+ input: app_id + '.in',
+ output: app_id,
+ configuration: launcherconf,
+ install_dir: pkgdatadir,
+)
+
+config_dir = '@0@/../..'.format(meson.current_build_dir())
+
+gnome.compile_resources(
+ app_id + '.src',
+ app_id + '.src.gresource.xml',
+ dependencies: [config_js],
+ source_dir: ['.', '../..', config_dir],
+ gresource_bundle: true,
+ install: true,
+ install_dir: pkgdatadir
+)
--- /dev/null
+/* The version of this package */
+var PACKAGE_VERSION = '@PACKAGE_VERSION@';
--- /dev/null
+jsconf = configuration_data()
+jsconf.set('PACKAGE_VERSION', meson.project_version())
+
+extensions_config = configure_file(
+ input: 'config.js.in',
+ output: 'config.js',
+ configuration: jsconf
+)
--- /dev/null
+imports.package.start({
+ name: '@PACKAGE_NAME@',
+ version: '@PACKAGE_VERSION@',
+ prefix: '@prefix@',
+ libdir: '@libdir@',
+});
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/Extensions/js">
+ <file>main.js</file>
+
+ <file>misc/config.js</file>
+ <file>misc/extensionUtils.js</file>
+ <file>misc/fileUtils.js</file>
+ </gresource>
+</gresources>
+++ /dev/null
-/* exported main */
-imports.gi.versions.Gdk = '3.0';
-imports.gi.versions.Gtk = '3.0';
-
-imports.package.initFormat();
-
-const Gettext = imports.gettext;
-const { Gdk, GLib, Gio, GObject, Gtk } = imports.gi;
-
-const _ = Gettext.gettext;
-
-const ExtensionUtils = imports.misc.extensionUtils;
-const { loadInterfaceXML } = imports.misc.fileUtils;
-
-const { ExtensionState, ExtensionType } = ExtensionUtils;
-
-const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
-const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
-
-function stripPrefix(string, prefix) {
- if (string.slice(0, prefix.length) == prefix)
- return string.slice(prefix.length);
- return string;
-}
-
-var Application = GObject.registerClass(
-class Application extends Gtk.Application {
- _init() {
- GLib.set_prgname('gnome-shell-extension-prefs');
- super._init({
- application_id: 'org.gnome.Extensions',
- flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
- });
- }
-
- get shellProxy() {
- return this._shellProxy;
- }
-
- vfunc_activate() {
- this._shellProxy.CheckForUpdatesRemote();
- this._window.present();
- }
-
- vfunc_startup() {
- super.vfunc_startup();
-
- let provider = new Gtk.CssProvider();
- let uri = 'resource:///org/gnome/Extensions/css/application.css';
- try {
- provider.load_from_file(Gio.File.new_for_uri(uri));
- } catch (e) {
- logError(e, 'Failed to add application style');
- }
- Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
- provider,
- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
-
- this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
- this._window = new ExtensionsWindow({ application: this });
- }
-
- vfunc_command_line(commandLine) {
- let [prgName_, uuid] = commandLine.get_arguments();
-
- if (uuid) {
- // Strip off "extension:///" prefix which fakes a URI, if it exists
- uuid = stripPrefix(uuid, 'extension:///');
-
- this._window.openPrefs(uuid);
- } else {
- this.activate();
- }
- return 0;
- }
-});
-
-var ExtensionsWindow = GObject.registerClass({
- GTypeName: 'ExtensionsWindow',
- Template: 'resource:///org/gnome/Extensions/ui/extensions-window.ui',
- InternalChildren: [
- 'userList',
- 'systemList',
- 'killSwitch',
- 'mainBox',
- 'mainStack',
- 'scrolledWindow',
- 'updatesBar',
- 'updatesLabel',
- ],
-}, class ExtensionsWindow extends Gtk.ApplicationWindow {
- _init(params) {
- super._init(params);
-
- this._startupUuid = null;
- this._loaded = false;
- this._prefsDialog = null;
- this._updatesCheckId = 0;
-
- this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment);
-
- let action;
- action = new Gio.SimpleAction({ name: 'show-about' });
- action.connect('activate', this._showAbout.bind(this));
- this.add_action(action);
-
- action = new Gio.SimpleAction({ name: 'logout' });
- action.connect('activate', this._logout.bind(this));
- this.add_action(action);
-
- this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
- this._settings.bind('disable-user-extensions',
- this._killSwitch, 'active',
- Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
-
- this._userList.set_sort_func(this._sortList.bind(this));
- this._userList.set_header_func(this._updateHeader.bind(this));
-
- this._systemList.set_sort_func(this._sortList.bind(this));
- this._systemList.set_header_func(this._updateHeader.bind(this));
-
- this._shellProxy.connectSignal('ExtensionStateChanged',
- this._onExtensionStateChanged.bind(this));
-
- this._scanExtensions();
- }
-
- get _shellProxy() {
- return this.application.shellProxy;
- }
-
- uninstall(uuid) {
- let row = this._findExtensionRow(uuid);
-
- let dialog = new Gtk.MessageDialog({
- transient_for: this,
- modal: true,
- text: _('Remove “%s”?').format(row.name),
- secondary_text: _('If you remove the extension, you need to return to download it if you want to enable it again'),
- });
-
- dialog.add_button(_('Cancel'), Gtk.ResponseType.CANCEL);
- dialog.add_button(_('Remove'), Gtk.ResponseType.ACCEPT)
- .get_style_context().add_class('destructive-action');
-
- dialog.connect('response', (dlg, response) => {
- if (response === Gtk.ResponseType.ACCEPT)
- this._shellProxy.UninstallExtensionRemote(uuid);
- dialog.destroy();
- });
- dialog.present();
- }
-
- openPrefs(uuid) {
- if (!this._loaded)
- this._startupUuid = uuid;
- else if (!this._showPrefs(uuid))
- this.present();
- }
-
- _showPrefs(uuid) {
- if (this._prefsDialog)
- return false;
-
- let row = this._findExtensionRow(uuid);
- if (!row || !row.hasPrefs)
- return false;
-
- let widget;
-
- try {
- widget = row.prefsModule.buildPrefsWidget();
- } catch (e) {
- widget = this._buildErrorUI(row, e);
- }
-
- this._prefsDialog = new Gtk.Window({
- application: this.application,
- default_width: 600,
- default_height: 400,
- modal: this.visible,
- type_hint: Gdk.WindowTypeHint.DIALOG,
- window_position: Gtk.WindowPosition.CENTER,
- });
-
- this._prefsDialog.set_titlebar(new Gtk.HeaderBar({
- show_close_button: true,
- title: row.name,
- visible: true,
- }));
-
- if (this.visible)
- this._prefsDialog.transient_for = this;
-
- this._prefsDialog.connect('destroy', () => {
- this._prefsDialog = null;
-
- if (!this.visible)
- this.destroy();
- });
-
- this._prefsDialog.add(widget);
- this._prefsDialog.show();
-
- return true;
- }
-
- _showAbout() {
- let aboutDialog = new Gtk.AboutDialog({
- authors: [
- 'Florian Müllner <fmuellner@gnome.org>',
- 'Jasper St. Pierre <jstpierre@mecheye.net>',
- 'Didier Roche <didrocks@ubuntu.com>',
- ],
- translator_credits: _('translator-credits'),
- program_name: _('Extensions'),
- comments: _('Manage your GNOME Extensions'),
- license_type: Gtk.License.GPL_2_0,
- logo_icon_name: 'org.gnome.Extensions',
- version: imports.package.version,
-
- transient_for: this,
- modal: true,
- });
- aboutDialog.present();
- }
-
- _logout() {
- this.application.get_dbus_connection().call(
- 'org.gnome.SessionManager',
- '/org/gnome/SessionManager',
- 'org.gnome.SessionManager',
- 'Logout',
- new GLib.Variant('(u)', [0]),
- null,
- Gio.DBusCallFlags.NONE,
- -1,
- null,
- (o, res) => {
- o.call_finish(res);
- });
- }
-
- _buildErrorUI(row, exc) {
- let scroll = new Gtk.ScrolledWindow({
- hscrollbar_policy: Gtk.PolicyType.NEVER,
- propagate_natural_height: true,
- });
-
- let box = new Gtk.Box({
- orientation: Gtk.Orientation.VERTICAL,
- spacing: 12,
- margin: 100,
- margin_bottom: 60,
- });
- scroll.add(box);
-
- let label = new Gtk.Label({
- label: '<span size="x-large">%s</span>'.format(_("Something’s gone wrong")),
- use_markup: true,
- });
- label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
- box.add(label);
-
- label = new Gtk.Label({
- label: _("We’re very sorry, but there’s been a problem: the settings for this extension can’t be displayed. We recommend that you report the issue to the extension authors."),
- justify: Gtk.Justification.CENTER,
- wrap: true,
- });
- box.add(label);
-
- let expander = new Expander({
- label: _("Technical Details"),
- margin_top: 12,
- });
- box.add(expander);
-
- let errortext = '%s\n\nStack trace:\n'.format(exc);
- // Indent stack trace.
- errortext +=
- exc.stack.split('\n').map(line => ' %s'.format(line)).join('\n');
-
- let buffer = new Gtk.TextBuffer({ text: errortext });
- let textview = new Gtk.TextView({
- buffer,
- wrap_mode: Gtk.WrapMode.WORD,
- monospace: true,
- editable: false,
- top_margin: 12,
- bottom_margin: 12,
- left_margin: 12,
- right_margin: 12,
- });
-
- let toolbar = new Gtk.Toolbar();
- let provider = new Gtk.CssProvider();
- provider.load_from_data(`* {
- border: 0 solid @borders;
- border-top-width: 1px;
- }`);
- toolbar.get_style_context().add_provider(
- provider,
- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
- );
-
- let copyButton = new Gtk.ToolButton({
- icon_name: 'edit-copy-symbolic',
- tooltip_text: _("Copy Error"),
- });
- toolbar.add(copyButton);
-
- copyButton.connect('clicked', w => {
- let clipboard = Gtk.Clipboard.get_default(w.get_display());
- // markdown for pasting in gitlab issues
- let lines = [
- 'The settings of extension %s had an error:'.format(row.uuid),
- '```', // '`' (xgettext throws up on odd number of backticks)
- exc.toString(),
- '```', // '`'
- '',
- 'Stack trace:',
- '```', // '`'
- exc.stack.replace(/\n$/, ''), // stack without trailing newline
- '```', // '`'
- '',
- ];
- clipboard.set_text(lines.join('\n'), -1);
- });
-
- let spacing = new Gtk.SeparatorToolItem({ draw: false });
- toolbar.add(spacing);
- toolbar.child_set_property(spacing, "expand", true);
-
- let urlButton = new Gtk.ToolButton({
- label: _("Homepage"),
- tooltip_text: _("Visit extension homepage"),
- no_show_all: true,
- visible: row.url !== '',
- });
- toolbar.add(urlButton);
-
- urlButton.connect('clicked', w => {
- let context = w.get_display().get_app_launch_context();
- Gio.AppInfo.launch_default_for_uri(row.url, context);
- });
-
- let expandedBox = new Gtk.Box({
- orientation: Gtk.Orientation.VERTICAL,
- });
- expandedBox.add(textview);
- expandedBox.add(toolbar);
-
- expander.add(expandedBox);
-
- scroll.show_all();
- return scroll;
- }
-
- _sortList(row1, row2) {
- return row1.name.localeCompare(row2.name);
- }
-
- _updateHeader(row, before) {
- if (!before || row.get_header())
- return;
-
- let sep = new Gtk.Separator({ orientation: Gtk.Orientation.HORIZONTAL });
- row.set_header(sep);
- }
-
- _findExtensionRow(uuid) {
- return [
- ...this._userList.get_children(),
- ...this._systemList.get_children(),
- ].find(c => c.uuid === uuid);
- }
-
- _onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
- let extension = ExtensionUtils.deserializeExtension(newState);
- let row = this._findExtensionRow(uuid);
-
- this._queueUpdatesCheck();
-
- // the extension's type changed; remove the corresponding row
- // and reset the variable to null so that we create a new row
- // below and add it to the appropriate list
- if (row && row.type !== extension.type) {
- row.destroy();
- row = null;
- }
-
- if (row) {
- if (extension.state === ExtensionState.UNINSTALLED)
- row.destroy();
- return; // we only deal with new and deleted extensions here
- }
- this._addExtensionRow(extension);
- }
-
- _scanExtensions() {
- this._shellProxy.ListExtensionsRemote(([extensionsMap], e) => {
- if (e) {
- if (e instanceof Gio.DBusError) {
- log('Failed to connect to shell proxy: %s'.format(e.toString()));
- this._mainStack.visible_child_name = 'noshell';
- } else {
- throw e;
- }
- return;
- }
-
- for (let uuid in extensionsMap) {
- let extension = ExtensionUtils.deserializeExtension(extensionsMap[uuid]);
- this._addExtensionRow(extension);
- }
- this._extensionsLoaded();
- });
- }
-
- _addExtensionRow(extension) {
- let row = new ExtensionRow(extension);
- row.show_all();
-
- if (row.type === ExtensionType.PER_USER)
- this._userList.add(row);
- else
- this._systemList.add(row);
- }
-
- _queueUpdatesCheck() {
- if (this._updatesCheckId)
- return;
-
- this._updatesCheckId = GLib.timeout_add_seconds(
- GLib.PRIORITY_DEFAULT, 1, () => {
- this._checkUpdates();
-
- this._updatesCheckId = 0;
- return GLib.SOURCE_REMOVE;
- });
- }
-
- _checkUpdates() {
- let nUpdates = this._userList.get_children().filter(c => c.hasUpdate).length;
-
- this._updatesLabel.label = Gettext.ngettext(
- '%d extension will be updated on next login.',
- '%d extensions will be updated on next login.',
- nUpdates).format(nUpdates);
- this._updatesBar.visible = nUpdates > 0;
- }
-
- _extensionsLoaded() {
- this._userList.visible = this._userList.get_children().length > 0;
- this._systemList.visible = this._systemList.get_children().length > 0;
-
- if (this._userList.visible || this._systemList.visible)
- this._mainStack.visible_child_name = 'main';
- else
- this._mainStack.visible_child_name = 'placeholder';
-
- this._checkUpdates();
-
- if (this._startupUuid)
- this._showPrefs(this._startupUuid);
- this._startupUuid = null;
- this._loaded = true;
- }
-});
-
-var Expander = GObject.registerClass({
- Properties: {
- 'label': GObject.ParamSpec.string(
- 'label', 'label', 'label',
- GObject.ParamFlags.READWRITE,
- null
- ),
- },
-}, class Expander extends Gtk.Box {
- _init(params = {}) {
- this._labelText = null;
-
- super._init(Object.assign(params, {
- orientation: Gtk.Orientation.VERTICAL,
- spacing: 0,
- }));
-
- this._frame = new Gtk.Frame({
- shadow_type: Gtk.ShadowType.IN,
- hexpand: true,
- });
-
- let eventBox = new Gtk.EventBox();
- this._frame.add(eventBox);
-
- let hbox = new Gtk.Box({
- spacing: 6,
- margin: 12,
- });
- eventBox.add(hbox);
-
- this._arrow = new Gtk.Image({
- icon_name: 'pan-end-symbolic',
- });
- hbox.add(this._arrow);
-
- this._label = new Gtk.Label({ label: this._labelText });
- hbox.add(this._label);
-
- this._revealer = new Gtk.Revealer();
-
- this._childBin = new Gtk.Frame({
- shadow_type: Gtk.ShadowType.IN,
- });
- this._revealer.add(this._childBin);
-
- // Directly chain up to parent for internal children
- super.add(this._frame);
- super.add(this._revealer);
-
- let provider = new Gtk.CssProvider();
- provider.load_from_data('* { border-top-width: 0; }');
- this._childBin.get_style_context().add_provider(
- provider,
- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
- );
-
- this._gesture = new Gtk.GestureMultiPress({
- widget: this._frame,
- button: 0,
- exclusive: true,
- });
- this._gesture.connect('released', (gesture, nPress) => {
- if (nPress == 1)
- this._revealer.reveal_child = !this._revealer.reveal_child;
- });
- this._revealer.connect('notify::reveal-child', () => {
- if (this._revealer.reveal_child)
- this._arrow.icon_name = 'pan-down-symbolic';
- else
- this._arrow.icon_name = 'pan-end-symbolic';
- });
- }
-
- get label() {
- return this._labelText;
- }
-
- set label(text) {
- if (this._labelText == text)
- return;
-
- if (this._label)
- this._label.label = text;
- this._labelText = text;
- this.notify('label');
- }
-
- add(child) {
- // set expanded child
- this._childBin.get_children().forEach(c => {
- this._childBin.remove(c);
- });
-
- if (child)
- this._childBin.add(child);
- }
-});
-
-var ExtensionRow = GObject.registerClass({
- GTypeName: 'ExtensionRow',
- Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui',
- InternalChildren: [
- 'nameLabel',
- 'descriptionLabel',
- 'versionLabel',
- 'authorLabel',
- 'updatesIcon',
- 'revealButton',
- 'revealer',
- ],
-}, class ExtensionRow extends Gtk.ListBoxRow {
- _init(extension) {
- super._init();
-
- this._app = Gio.Application.get_default();
- this._extension = extension;
- this._prefsModule = null;
-
- this._actionGroup = new Gio.SimpleActionGroup();
- this.insert_action_group('row', this._actionGroup);
-
- let action;
- action = new Gio.SimpleAction({
- name: 'show-prefs',
- enabled: this.hasPrefs,
- });
- action.connect('activate', () => this.get_toplevel().openPrefs(this.uuid));
- this._actionGroup.add_action(action);
-
- action = new Gio.SimpleAction({
- name: 'show-url',
- enabled: this.url !== '',
- });
- action.connect('activate', () => {
- Gio.AppInfo.launch_default_for_uri(
- this.url, this.get_display().get_app_launch_context());
- });
- this._actionGroup.add_action(action);
-
- action = new Gio.SimpleAction({
- name: 'uninstall',
- enabled: this.type === ExtensionType.PER_USER,
- });
- action.connect('activate', () => this.get_toplevel().uninstall(this.uuid));
- this._actionGroup.add_action(action);
-
- action = new Gio.SimpleAction({
- name: 'enabled',
- state: new GLib.Variant('b', false),
- });
- action.connect('activate', () => {
- let state = action.get_state();
- action.change_state(new GLib.Variant('b', !state.get_boolean()));
- });
- action.connect('change-state', (a, state) => {
- if (state.get_boolean())
- this._app.shellProxy.EnableExtensionRemote(this.uuid);
- else
- this._app.shellProxy.DisableExtensionRemote(this.uuid);
- });
- this._actionGroup.add_action(action);
-
- this._nameLabel.label = this.name;
-
- let desc = this._extension.metadata.description.split('\n')[0];
- this._descriptionLabel.label = desc;
-
- this._revealButton.connect('clicked', () => {
- this._revealer.reveal_child = !this._revealer.reveal_child;
- });
- this._revealer.connect('notify::reveal-child', () => {
- if (this._revealer.reveal_child)
- this._revealButton.get_style_context().add_class('expanded');
- else
- this._revealButton.get_style_context().remove_class('expanded');
- });
-
- this.connect('destroy', this._onDestroy.bind(this));
-
- this._extensionStateChangedId = this._app.shellProxy.connectSignal(
- 'ExtensionStateChanged', (p, sender, [uuid, newState]) => {
- if (this.uuid !== uuid)
- return;
-
- this._extension = ExtensionUtils.deserializeExtension(newState);
- this._updateState();
- });
- this._updateState();
- }
-
- get uuid() {
- return this._extension.uuid;
- }
-
- get name() {
- return this._extension.metadata.name;
- }
-
- get hasPrefs() {
- return this._extension.hasPrefs;
- }
-
- get hasUpdate() {
- return this._extension.hasUpdate || false;
- }
-
- get type() {
- return this._extension.type;
- }
-
- get creator() {
- return this._extension.metadata.creator || '';
- }
-
- get url() {
- return this._extension.metadata.url || '';
- }
-
- get version() {
- return this._extension.metadata.version || '';
- }
-
- _updateState() {
- let state = this._extension.state === ExtensionState.ENABLED;
-
- let action = this._actionGroup.lookup('enabled');
- action.set_state(new GLib.Variant('b', state));
- action.enabled = this._canToggle();
-
- this._updatesIcon.visible = this.hasUpdate;
-
- this._versionLabel.label = this.version.toString();
- this._versionLabel.visible = this.version !== '';
-
- this._authorLabel.label = this.creator.toString();
- this._authorLabel.visible = this.creator !== '';
- }
-
- _onDestroy() {
- if (!this._app.shellProxy)
- return;
-
- if (this._extensionStateChangedId)
- this._app.shellProxy.disconnectSignal(this._extensionStateChangedId);
- this._extensionStateChangedId = 0;
- }
-
- _canToggle() {
- return this._extension.canChange;
- }
-
- get prefsModule() {
- // give extension prefs access to their own extension object
- ExtensionUtils.getCurrentExtension = () => this._extension;
-
- if (!this._prefsModule) {
- ExtensionUtils.installImporter(this._extension);
-
- this._prefsModule = this._extension.imports.prefs;
- this._prefsModule.init(this._extension.metadata);
- }
-
- return this._prefsModule;
- }
-});
-
-function initEnvironment() {
- // Monkey-patch in a "global" object that fakes some Shell utilities
- // that ExtensionUtils depends on.
- window.global = {
- log(...args) {
- print(args.join(', '));
- },
-
- logError(s) {
- log('ERROR: %s'.format(s));
- },
-
- userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']),
- };
-}
-
-function main(argv) {
- initEnvironment();
-
- new Application().run(argv);
-}
app_id = 'org.gnome.Extensions'
prgname = 'gnome-shell-extension-prefs'
-launcherconf = configuration_data()
-launcherconf.set('app_id', app_id)
-launcherconf.set('PACKAGE_NAME', meson.project_name())
-launcherconf.set('PACKAGE_VERSION', meson.project_version())
-launcherconf.set('prefix', prefix)
-launcherconf.set('libdir', libdir)
-launcherconf.set('pkgdatadir', pkgdatadir)
-launcherconf.set('gjs', gjs.path())
-
-configure_file(
- input: prgname + '.in',
- output: prgname,
- configuration: launcherconf,
- install_dir: bindir,
- install_mode: 'rwxr-xr-x',
-)
-
-configure_file(
- input: app_id + '.in',
- output: app_id,
- configuration: launcherconf,
- install_dir: pkgdatadir,
-)
-
-config_dir = '@0@/..'.format(meson.current_build_dir())
-
-gnome.compile_resources(
- app_id + '.src',
- app_id + '.src.gresource.xml',
- dependencies: [config_js],
- source_dir: ['.', '..', config_dir],
- gresource_bundle: true,
- install: true,
- install_dir: pkgdatadir
-)
-
-gnome.compile_resources(
- app_id + '.data',
- app_id + '.data.gresource.xml',
- gresource_bundle: true,
- install: true,
- install_dir: pkgdatadir
-)
+subdir('data')
+subdir('js')
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gresources>
- <gresource prefix="/org/gnome/Extensions">
- <file>css/application.css</file>
-
- <file>ui/extension-row.ui</file>
- <file>ui/extensions-window.ui</file>
- </gresource>
-</gresources>
+++ /dev/null
-imports.package.start({
- name: '@PACKAGE_NAME@',
- version: '@PACKAGE_VERSION@',
- prefix: '@prefix@',
- libdir: '@libdir@',
-});
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<gresources>
- <gresource prefix="/org/gnome/Extensions/js">
- <file>main.js</file>
-
- <file>misc/config.js</file>
- <file>misc/extensionUtils.js</file>
- <file>misc/fileUtils.js</file>
- </gresource>
-</gresources>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.0 -->
-<interface>
- <requires lib="gtk+" version="3.20"/>
- <template class="ExtensionRow" parent="GtkListBoxRow">
- <property name="visible">True</property>
- <property name="activatable">False</property>
- <child>
- <object class="GtkGrid">
- <property name="visible">True</property>
- <property name="margin">12</property>
- <property name="column_spacing">12</property>
- <child>
- <object class="GtkLabel" id="nameLabel">
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkImage" id="updatesIcon">
- <property name="no_show_all">True</property>
- <property name="icon_name">software-update-available-symbolic</property>
- <style>
- <class name="warning"/>>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="hexpand">True</property>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="prefsButton">
- <property name="no_show_all">True</property>
- <property name="visible"
- bind-source="prefsButton"
- bind-property="sensitive"
- bind-flags="sync-create"/>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="valign">center</property>
- <property name="action-name">row.show-prefs</property>
- <style>
- <class name="circular"/>>
- <class name="image-button"/>>
- </style>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="icon_name">emblem-system-symbolic</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkSwitch">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="valign">center</property>
- <property name="action-name">row.enabled</property>
- </object>
- </child>
- <child>
- <object class="GtkSeparator">
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="revealButton">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="valign">center</property>
- <style>
- <class name="details-button"/>
- <class name="image-button"/>
- <class name="flat"/>
- </style>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="icon_name">pan-end-symbolic</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkRevealer" id="revealer">
- <property name="visible">True</property>
- <child>
- <object class="GtkGrid">
- <property name="visible">True</property>
- <property name="margin_top">12</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">12</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Description</property>
- <property name="xalign">0</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="descriptionLabel">
- <property name="visible">True</property>
- <property name="ellipsize">end</property>
- <property name="max_width_chars">60</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible"
- bind-source="versionLabel"
- bind-property="visible"
- bind-flags="sync-create"/>
- <property name="no_show_all">True</property>
- <property name="label" translatable="yes">Version</property>
- <property name="xalign">0</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="versionLabel">
- <property name="no_show_all">True</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible"
- bind-source="authorLabel"
- bind-property="visible"
- bind-flags="sync-create"/>
- <property name="no_show_all">True</property>
- <property name="label" translatable="yes">Author</property>
- <property name="xalign">0</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="authorLabel">
- <property name="no_show_all">True</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Website</property>
- <property name="action_name">row.show-url</property>
- <property name="valign">end</property>
- <property name="margin-top">12</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="removeButton">
- <property name="visible"
- bind-source="removeButton"
- bind-property="sensitive"
- bind-flags="sync-create"/>
- <property name="no_show_all">True</property>
- <property name="label" translatable="yes">Remove…</property>
- <property name="action_name">row.uninstall</property>
- <property name="hexpand">True</property>
- <property name="halign">end</property>
- <property name="valign">end</property>
- <style>
- <class name="destructive-action"/>
- </style>
- </object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">3</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- <property name="width">7</property>
- </packing>
- </child>
- </object>
- </child>
- </template>
-</interface>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.0 -->
-<interface>
- <requires lib="gtk+" version="3.20"/>
- <menu id="primary-menu">
- <section>
- <item>
- <attribute name="label" translatable="yes">Help</attribute>
- <attribute name="action">win.show-help</attribute>
- </item>
- <item>
- <attribute name="label" translatable="yes">About Extensions</attribute>
- <attribute name="action">win.show-about</attribute>
- </item>
- </section>
- </menu>
- <object class="GtkPopover" id="infoPopover">
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="margin">12</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">To find and add extensions, visit <a href="https://extensions.gnome.org">extensions.gnome.org</a>.</property>
- <property name="use_markup">True</property>
- <property name="xalign">0</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Warning</property>
- <property name="xalign">0</property>
- <property name="margin_top">6</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Extensions can cause system issues, including performance problems. If you encounter problems with your system, it is recommended to disable all extensions.</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">40</property>
- <property name="xalign">0</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- <template class="ExtensionsWindow" parent="GtkApplicationWindow">
- <property name="default_width">800</property>
- <property name="default_height">500</property>
- <child type="titlebar">
- <object class="GtkHeaderBar">
- <property name="visible">True</property>
- <property name="title" translatable="yes">Extensions</property>
- <property name="show_close_button">True</property>
- <child>
- <object class="GtkMenuButton">
- <property name="visible">True</property>
- <property name="popover">infoPopover</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="icon_name">dialog-information-symbolic</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkMenuButton" id="menuButton">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="menu_model">primary-menu</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="icon_name">open-menu-symbolic</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- <child>
- <object class="GtkSwitch" id="killSwitch">
- <property name="visible">True</property>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkStack" id="mainStack">
- <property name="visible">True</property>
- <property name="transition_type">crossfade</property>
- <property name="vexpand">True</property>
- <child>
- <object class="GtkScrolledWindow" id="scrolledWindow">
- <property name="visible">True</property>
- <property name="hscrollbar_policy">never</property>
- <child>
- <object class="GtkViewport">
- <property name="visible">True</property>
- <child>
- <object class="GtkBox" id="mainBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="halign">center</property>
- <property name="margin">36</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel">
- <property name="visible"
- bind-source="userList"
- bind-property="visible"
- bind-flags="sync-create"/>
- <property name="halign">start</property>
- <property name="hexpand">True</property>
- <property name="label" translatable="yes">Manually Installed</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- </child>
- <child>
- <object class="GtkListBox" id="userList">
- <property name="visible">True</property>
- <property name="selection_mode">none</property>
- <property name="margin_bottom">24</property>
- <style>
- <class name="frame"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible"
- bind-source="systemList"
- bind-property="visible"
- bind-flags="sync-create"/>
- <property name="halign">start</property>
- <property name="hexpand">True</property>
- <property name="label" translatable="yes">Built-In</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- </child>
- <child>
- <object class="GtkListBox" id="systemList">
- <property name="visible">True</property>
- <property name="selection_mode">none</property>
- <style>
- <class name="frame"/>
- </style>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="name">main</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="margin">32</property>
- <property name="spacing">6</property>
- <property name="valign">center</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="pixel_size">96</property>
- <property name="icon_name">org.gnome.Extensions-symbolic</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">No Installed Extensions</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.44"/>
- </attributes>
- </object>
- </child>
- </object>
- <packing>
- <property name="name">placeholder</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="margin_left">100</property>
- <property name="margin_right">100</property>
- <property name="margin_top">100</property>
- <property name="margin_bottom">60</property>
- <property name="orientation">vertical</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Something’s gone wrong</property>
- <attributes>
- <attribute name="scale" value="1.44"/>
- </attributes>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="label" translatable="yes">We’re very sorry, but it was not possible to get the list of installed extensions. Make sure you are logged into GNOME and try again.</property>
- <property name="justify">center</property>
- <property name="wrap">True</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- </child>
- </object>
- <packing>
- <property name="name">noshell</property>
- </packing>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkActionBar" id="updatesBar">
- <property name="no_show_all">True</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="pixel-size">24</property>
- <property name="margin">6</property>
- <property name="icon_name">software-update-available-symbolic</property>
- <style>
- <class name="warning"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="label">Extension Updates Ready</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="updatesLabel">
- <property name="visible">True</property>
- <property name="halign">start</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkButton">
- <property name="label" translatable="yes">Log Out…</property>
- <property name="visible">True</property>
- <property name="valign">center</property>
- <property name="action-name">win.logout</property>
- <property name="receives_default">True</property>
- <style>
- <class name="suggested-action"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- </template>
-</interface>
overrides:
- files: js/**
excludedFiles:
- - js/extensionPrefs/*
+ - js/extensionPrefs/**
- js/portalHelper/*
globals:
global: readonly
data/org.gnome.Shell.desktop.in.in
data/org.gnome.shell.gschema.xml.in
data/org.gnome.Shell.PortalHelper.desktop.in.in
-js/extensionPrefs/main.js
-js/extensionPrefs/ui/extension-row.ui
-js/extensionPrefs/ui/extensions-window.ui
+js/extensionPrefs/js/main.js
+js/extensionPrefs/data/ui/extension-row.ui
+js/extensionPrefs/data/ui/extensions-window.ui
js/gdm/authPrompt.js
js/gdm/loginDialog.js
js/gdm/util.js